<!-- 
时间 : 2025.01.06:16.40.13
名称 : G_QueryFun
类型 : 组件
功能 : 查询 + 功能按键(表单设置、刷新、打印)
编码 : 村长有人偷包谷
 -->
<script setup>
import { ref, onMounted, markRaw } from 'vue'
import {
    Search, Setting,
    Printer,
    RefreshLeft,
    Filter,
    Sort,
    Download,
    Refresh,
    Upload,
    Edit
} from '@element-plus/icons-vue'
// import U from "@utils/index.js"
// import * as XLSX from 'xlsx'
import { useRouter } from 'vue-router'

const props = defineProps(['Config']);
const { btnConfig, queryConfig, _FilterConfig } = props.Config
onMounted(() => {
    queryList.value = queryConfig?.Options.length ? queryConfig : []
    if (btnConfig?.length) {
        btnList.value = defaultFeatures.filter(e => {
            return btnConfig.find(id => {
                return id == e.id
            })
        })
    }
})

const defaultFeatures = [
    {
        name: '查询',
        id: '9',
        icon: markRaw(Search)
    },
    {
        name: '清空',
        id: '1',
        icon: markRaw(Refresh)
    },
    {
        name: '强制刷新',
        id: '2',
        icon: markRaw(RefreshLeft)
    },
    {
        name: '打印',
        id: '3',
        icon: markRaw(Printer)
    },
    {
        name: '导出',
        id: '4',
        icon: markRaw(Download)
    },
    {
        name: '导入',
        id: '5',
        icon: markRaw(Upload)
    },
    {
        name: '排序',
        id: '6',
        icon: markRaw(Sort)
    },
    {
        name: '筛选',
        id: '7',
        icon: markRaw(Filter)
    },
    {
        name: '设置表格',
        id: '8',
        icon: markRaw(Setting)
    },
    {
        name: '编辑模式',
        id: '10',
        icon: markRaw(Edit)
    }
]
const btnList = ref(defaultFeatures)

const router = useRouter()
const O_Feature = (data, ExposeData) => {
    console.log('功能按键:', data.name, 'id:', data.id, "父元素数据：", ExposeData);

    if (data.id == 1) {
        D_HeadForm.value = {};
        handleFilterReset()
        props.Config.Send_Form(D_HeadForm.value);
    } else if (data.id == 2) {
        router.go(0);
    } else if (data.id == 3 && ExposeData) {
        print(ExposeData)
    } else if (data.id == 4 && ExposeData) {
        Exlsx(ExposeData)
    } else if (data.id == 9) {
        dialogVisible.value = true
    } else {
        props.Config.O_Feature(data);
    }

}

const queryList = ref({
    Options: [
        {
            fields: 'name',
            type: 'input',
            placeholder: '请输入关键字关键词'
        },
        {
            fields: 'project',
            type: 'select',
            placeholder: '负责人'
        },
        {
            fields: 'principal',
            type: 'select',
            placeholder: '项目'
        },
        {
            fields: 'state',
            type: 'select',
            placeholder: '状态'
        },

    ],
    project: [

        {
            name: 'GL11',
        },
        {
            name: 'GL12'
        },
        {
            name: 'GL13'
        },
        {
            name: 'GL14'
        },
    ],
    principal: [
        {
            name: '全部'
        },
        {
            name: '小明',
        },
        {
            name: '小白'
        },
        {
            name: '小花'
        },
        {
            name: '小红'
        },
    ],
    state: [

        {
            name: '草稿',
        },
        {
            name: '待审批'
        },
        {
            name: '待测试'
        },
        {
            name: '完成'
        },
    ],
})

// 查询
const D_HeadForm = ref({
})
// 防抖函数
const debounce = (fn, delay) => {
    let timer = null
    return function (...args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, delay)
    }
}

// 使用防抖
const O_input = debounce(() => {
    Send_Form()
}, 500)

const O_chenge = (e) => {
    console.log('选择内容', e);
    Send_Form()
}

const Send_Form = () => {
    const obj = cleanObject({ ...D_HeadForm.value })
    console.log("发送内容", obj);
    props.Config.Send_Form(obj)
}

function cleanObject(obj) {
    // 遍历对象的每个属性
    Object.keys(obj).forEach(key => {
        // 检查属性值是否为 null、undefined 或空字符串
        if (obj[key] === null || obj[key] === undefined || obj[key] === "") {
            delete obj[key]; // 删除该属性
        }
    });
    return obj; // 返回清理后的对象
}
//-------------------- 打印
// 优化打印函数
const printFrame = ref(null);
// 打印处理函数
const print = ({ _title, _tableHeader, _tableData }) => {
    console.log('打印内容', _title, _tableHeader, _tableData);
    if (!printFrame.value) return;

    const formatCell = (row, col) => {
        if (props.Config.formatCellContent) {
            return props.Config.formatCellContent(row, col);
        }
        return row[col.prop] || '-';
    };

    const printDoc = printFrame.value.contentWindow.document;
    const printContent = `
        <!DOCTYPE html>
        <html>
            <head>
                <title>${_title}</title>
                <style>
                    ${getPrintStyles()}
                </style>
            </head>
            <body>
                ${getPrintHeader(_title)}
                ${getPrintTable(_tableHeader, _tableData, formatCell)}
            </body>
        </html>
    `;

    printDoc.open();
    printDoc.write(printContent);
    printDoc.close();

    printFrame.value.contentWindow.focus();
    printFrame.value.contentWindow.print();
}

// 打印样式
const getPrintStyles = () => `
    body { 
        font-family: Arial, sans-serif;
        padding: 20px;
    }
    .print-header {
        text-align: center;
        margin-bottom: 20px;
    }
    .print-header h2 {
        margin: 0;
        font-size: 16px;
    }
    .print-header p {
        margin: 8px 0;
        color: #666;
        font-size: 12px;
    }
    .print-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 12px;
    }
    .print-table th {
        background-color: #f5f7fa;
        font-weight: bold;
        text-align: center;
        padding: 12px 8px;
    }
    .print-table td {
        padding: 8px;
        text-align: center;
    }
    .print-table th, .print-table td {
        border: 1px solid #dcdfe6;
    }
    .print-table tr:nth-child(even) {
        background-color: #fafafa;
    }
    @media print {
        @page {
            size: A4 landscape;
            margin: 1cm;
        }
    }
`;
// 打印头部
const getPrintHeader = (_title) => `
    <div class="print-header">
        <h2>${_title}</h2>
        <p>打印时间：${new Date().toLocaleString()}</p>
    </div>
`;

// 打印表格
const getPrintTable = (_tableHeader, _tableData, formatCell) => `
    <table class="print-table">
        <thead>
            <tr>
                <th style="width: 60px">序号</th>
                ${_tableHeader.map(item => `<th>${item.label}</th>`).join('')}
            </tr>
        </thead>
        <tbody>
            ${_tableData.map((row, index) => `
                <tr>
                    <td>${index + 1}</td>
                    ${_tableHeader.map(col => `
                        <td>${formatCell(row, col)}</td>
                    `).join('')}
                </tr>
            `).join('')}
        </tbody>
    </table>
`;

// -------------------- 打印结束

// 表格导出xlsx
const Exlsx = ({ _tableHeader, _tableData, _title }) => {
    if (!_tableHeader && !_tableData) {
        U.Tips(0, '暂无可导出数据')
        return;
    }
    // 处理表头
    const headers = _tableHeader.map(item => item.label);
    const keys = _tableHeader.map(item => item.prop);

    // 处理数据
    const data = [headers]; // 将表头作为第一行
    _tableData.forEach((item, index) => {
        const row = [];
        row.push(index + 1); // 添加序号
        keys.forEach(key => {
            row.push(item[key] || '-');
        });
        data.push(row);
    });

    // 创建工作簿和工作表
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet(data);

    // 设置列宽
    const colWidths = [{ wch: 8 }]; // 序号列宽
    headers.forEach(() => colWidths.push({ wch: 15 }));
    ws['!cols'] = colWidths;

    // 设置表头样式
    const headerStyle = {
        font: { bold: true, color: { rgb: "FFFFFF" } },
        fill: { fgColor: { rgb: "4F81BD" } },
        alignment: { horizontal: "center", vertical: "center" }
    };

    // 设置单元格样式
    const cellStyle = {
        alignment: { horizontal: "center", vertical: "center" },
        border: {
            top: { style: 'thin' },
            bottom: { style: 'thin' },
            left: { style: 'thin' },
            right: { style: 'thin' }
        }
    };

    // 应用样式
    const range = XLSX.utils.decode_range(ws['!ref']);
    for (let R = range.s.r; R <= range.e.r; R++) {
        for (let C = range.s.c; C <= range.e.c; C++) {
            const cell_address = { c: C, r: R };
            const cell_ref = XLSX.utils.encode_cell(cell_address);
            if (!ws[cell_ref]) continue;

            ws[cell_ref].s = R === 0 ? headerStyle : cellStyle;
        }
    }

    // 添加工作表到工作簿
    XLSX.utils.book_append_sheet(wb, ws, _title);

    // 导出文件
    XLSX.writeFile(wb, `${_title}-${new Date().toLocaleDateString()}.xlsx`);
}


const Expose = (data, ObjData) => {
    console.log('Expose', data, ObjData);
    O_Feature(data, ObjData)
}


// 添加响应式变量
const dialogVisible = ref(false)
const filterForm = ref({})

// 添加处理方法
const handleFilterSubmit = () => {
    props.Config.Send_Form(filterForm.value)
    dialogVisible.value = false
}

const handleFilterReset = () => {
    filterForm.value = {}
}


// 获取查询条件标签
const getFilterLabel = (key) => {
    const item = _FilterConfig?.find(item => item.prop === key)
    return item?.label || key
}

// 移除查询条件
const handleRemoveFilter = (key) => {
    delete filterForm.value[key]
    props.Config.Send_Form(filterForm.value)
}



defineExpose({
    Expose
});
</script>

<template>
    <div id='G_QueryFun'>
        <div class="left">
            <!-- <div class="item" v-for="(o, i) in queryList.Options" :key='i'>
                <el-input v-if="o.type == 'input'" v-model="D_HeadForm[o.fields]" style="width: 240px"
                    :placeholder="o.placeholder" @input="O_input" clearable :prefix-icon="Search" />
                <el-date-picker v-else-if="o.type == 'date'" v-model="D_HeadForm[o.fields]" :type="o.dateType || 'date'"
                    :placeholder="o.placeholder" :format="o.format || 'YYYY-MM-DD'"
                    :value-format="o.valueFormat || 'YYYY-MM-DD'" :start-placeholder="o.startPlaceholder"
                    :end-placeholder="o.endPlaceholder" :disabled="o.disabled" :clearable="o.clearable !== false"
                    @change="O_chenge" style="width: 140px" />
                <el-select v-else-if="o.type == 'select'" v-model="D_HeadForm[o.fields]" filterable clearable
                    :placeholder="o.placeholder" @change="O_chenge" style="width: 120px">
                    <el-option v-for="(So, idx) in queryList[o.fields]" :key="idx" :label="So.name"
                        :value="So.value ? So.value : So.name" />
                </el-select>
            </div> -->
            <div>
                查询条件：
                <el-tag v-for="(value, key) in filterForm" :key="key" closable @close="handleRemoveFilter(key)"
                    class="filter-tag">
                    {{ getFilterLabel(key) }}: {{ value }}
                </el-tag>
                <el-tag v-if="!Object.keys(filterForm).length" type="info">暂无查询条件</el-tag>
            </div>
        </div>
        <div class="right">
            <div class="item" v-for="(o, i) in btnList">
                <div @click="O_Feature(o)">
                    <el-tooltip class="box-item" effect="dark" :content="o.name" placement="top">
                        <el-icon>
                            <component :is="o.icon" />
                        </el-icon>
                    </el-tooltip>
                </div>
            </div>
        </div>
    </div>


    <iframe ref="printFrame" style="display: none;"></iframe>




    <el-dialog v-model="dialogVisible" title="高级查询" width="600px">
        <el-form :model="filterForm" label-width="160px" style="padding-right: 20px;">
            <el-form-item v-for="item in _FilterConfig" :key="item.prop" :label="item.label">
                <el-input v-if="item.type === 'input'" v-model="filterForm[item.prop]"
                    :placeholder="item.placeholder" />
                <el-select v-if="item.type === 'select'" v-model="filterForm[item.prop]" :placeholder="item.placeholder"
                    clearable>
                    <el-option v-for="option in item.options" :key="option.value" :label="option.label"
                        :value="option.value" />
                </el-select>
                <el-date-picker v-if="item.type === 'date'" v-model="filterForm[item.prop]" type="date"
                                style="width: 100%;"
                    format="YYYY-MM-DD" value-format="YYYY-MM-DD" :placeholder="item.placeholder" />
                <el-date-picker v-if="item.type === 'dates'" v-model="filterForm[item.prop]" type="month"
                style="width: 100%;"
                    :placeholder="item.placeholder" format="YYYY-MM" value-format="YYYY-MM" />
            </el-form-item>
        </el-form>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="dialogVisible = false">取消</el-button>
                <el-button @click="handleFilterReset">重置</el-button>
                <el-button type="primary" @click="handleFilterSubmit">确定</el-button>
            </span>
        </template>
    </el-dialog>
</template>

<style lang='less' scoped>
#G_QueryFun {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 12px 0;

    gap: 16px;

    .filter-tag {
        margin: 0 4px;
        margin-bottom: 4px;
    }

    .left {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: 12px;


    }

    .right {
        display: flex;
        align-items: center;
        gap: 8px;

        .item {
            padding: 8px;
            border-radius: 4px;
            cursor: pointer;
            color: #606266;
            transition: all 0.2s ease;

            &:hover {
                color: var(--el-color-primary);
                background: var(--el-color-primary-light-9);
            }

            .el-icon {
                font-size: 16px;
                vertical-align: middle;
            }
        }
    }

    @media screen and (max-width: 768px) {
        flex-direction: column;
        align-items: flex-start;

        .right {
            width: 100%;
            justify-content: flex-end;
            margin-top: 12px;
        }
    }
}
</style>